package org.etlt.load;

import org.apache.commons.lang3.StringUtils;
import org.etlt.SettingCheck;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class DmlSetting implements SettingCheck {

    public static final String QUESTION_MARK = "?";

    public static final String ENTITY_IDENTIFIER = "@";

    public static final String REPLACE_EXTRACTOR_COLUMNS = "[[usingExtractorColumns]]";

    public static final String COMMA_MARK = ",";

    private String dml;

    private final String id;

    private String when;

    private boolean usingExtractorColumns;

    private boolean multiValue = false;

    private int repeat = 1;

    private String standardSql;

    private boolean tolerate = false;

    private List<String> parameters = new ArrayList<>();

    private List<DmlEntitySetting> dmlEntitySettings = new ArrayList<>();

    public DmlSetting(String id) {
        this.id = id;
    }

    public List<DmlEntitySetting> getDmlEntitySettings() {
        return new ArrayList<>(dmlEntitySettings);
    }

    public void addEntitySetting(DmlEntitySetting dmlEntitySetting){
        if(this.dmlEntitySettings.contains(dmlEntitySetting)){
            throw new IllegalArgumentException("dml entity setting exists: " + dmlEntitySetting.getName());
        }
        this.dmlEntitySettings.add(dmlEntitySetting);
    }

    public void parse() {
        String startFlag = "#{";
        String endFlag = "}";
        StringBuilder stringBuilder = new StringBuilder();
        int start = 0;
        for (int indexOfStart = dml.indexOf(startFlag, start),indexOfEnd = dml.indexOf(endFlag, start);
             indexOfStart != -1 && indexOfEnd != -1;
             indexOfStart = dml.indexOf(startFlag, start), indexOfEnd = dml.indexOf(endFlag, start)) {
            stringBuilder.append(dml, start, indexOfStart);
            start = indexOfEnd + 1;
            int existing = StringUtils.countMatches(stringBuilder, QUESTION_MARK);
            addParameter(existing, dml.substring(indexOfStart + startFlag.length(), indexOfEnd));
            stringBuilder.append(QUESTION_MARK);
        }
        stringBuilder.append(dml.substring(start));
        standardSql = stringBuilder.toString();
    }

    private void addParameter(int index, String expression){
        for(;index > this.parameters.size();){
            this.parameters.add(null);
        }
        this.parameters.add(index, expression);
    }

    public String getDml() {
        return dml;
    }

    public void setDml(String dml) {
        this.dml = dml;
    }

    public String getWhen() {
        return when;
    }

    public void setWhen(String when) {
        this.when = when;
    }

    public String getStandardSql() {
        return standardSql;
    }

    public String getStandardSql(int count) {
        String sql = getStandardSql();
        if(isUsingExtractorColumns()) {
            if (!sql.contains(REPLACE_EXTRACTOR_COLUMNS))
                throw new IllegalArgumentException("if usingExtractorColumns is set to true, the sql should contain " + REPLACE_EXTRACTOR_COLUMNS);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < count; i++) {
                stringBuilder.append(QUESTION_MARK).append(",");
            }
            if (stringBuilder.length() > 0) {
                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            }
            sql = sql.replace(REPLACE_EXTRACTOR_COLUMNS, stringBuilder.toString());
        }
        return sql;
    }

    public List<String> getParameters() {
        return parameters;
    }

    public String getParameter(int index) {
        if(index >= this.parameters.size())
            return null;
        return parameters.get(index);
    }


    public boolean isTolerate() {
        return tolerate;
    }

    public void setTolerate(boolean tolerate) {
        this.tolerate = tolerate;
    }

    public boolean isUsingExtractorColumns() {
        return usingExtractorColumns;
    }

    public void setUsingExtractorColumns(boolean usingExtractorColumns) {
        this.usingExtractorColumns = usingExtractorColumns;
    }

    public boolean isMultiValue() {
        return multiValue;
    }

    public void setMultiValue(boolean multiValue) {
        this.multiValue = multiValue;
    }

    public int getRepeat() {
        return repeat;
    }

    public void setRepeat(int repeat) {
        if(repeat <= 0)
            throw new IllegalArgumentException("repeat value is illegal: " + repeat);
        this.repeat = repeat;
    }

    public String getId() {
        return id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        DmlSetting that = (DmlSetting) o;
        return getId().equals(that.getId());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId());
    }

    @Override
    public void check() {
        assertName("id", getId());
    }
}
